Skip to main content

Read inventory levels

Business scenario

When stock levels change in Qoyod — because of a purchase, a sale, a manual adjustment, or a stock take — the integrated system does not automatically know. A retail storefront displaying available quantities, a warehouse management system tracking locations, or an order management tool checking fulfilment feasibility all depend on accurate, current stock figures. If those figures are not refreshed from Qoyod on a schedule, the integrated system operates on stale data: it may allow orders for items that are out of stock, or block orders for items that are available.

This use case describes how an integration reads current inventory levels from Qoyod and writes them to the integrated system. Qoyod is the source of truth for stock quantities. The integration periodically queries Qoyod for product data — including per-location stock figures — and applies the results to the integrated system's own records.

Qoyod does not push changes. All updates flow from the integration polling Qoyod and acting on what it receives. If polling stops, the integrated system's stock figures diverge from Qoyod's.

When to use this

Use this when:

  • Your integrated system needs to display or act on current stock quantities that Qoyod holds.
  • Stock levels in Qoyod change through Qoyod-side transactions (purchases, sales, adjustments, stock takes) and the integrated system must reflect those changes.
  • You need to check the stock level for a specific product by its Qoyod ID or SKU before processing an order.
  • You want to filter products by category or SKU to refresh a subset of your catalog.

Do not use this when:

Prerequisites

  • A valid OAuth 2.0 access token, or an API key, for the Qoyod account you are integrating with. Include it as a request header on every call.
  • Products with track_quantity set to 1 in Qoyod. Only tracked products carry stock data in the inventories array. Products with track_quantity: 0 return an empty inventories array.
  • The Qoyod product ID or SKU for any product you intend to query individually. If you have not yet stored Qoyod product IDs in your integrated system, run the list endpoint first and match records by SKU.
  • Awareness of your polling cadence. Review Sync frequency before deciding how often to poll.

Sequence diagram

Step-by-step

1. Authenticate

All requests require an Authorization header. Pass your OAuth 2.0 access token as a Bearer token, or your API key directly.

Authorization header — OAuth 2.0 access token
Authorization: Bearer {your_access_token}
Authorization header — API key
Authorization: {your_api_key}

2. Poll for all products with stock levels

Send GET /2.0/products to retrieve your product catalog with per-location stock figures. Use per_page to control page size and page to paginate through results.

List products — basic poll
curl -X GET "https://api.qoyod.com/2.0/products?page=1&per_page=100" \
-H "Authorization: Bearer {your_access_token}"

The response contains a products array and a pagination object.

Response — 200 OK (excerpt)
{
"products": [
{
"id": 42,
"name_en": "Blue Widget",
"sku": "BW-001",
"track_quantity": 1,
"inventories": [
{
"id": 3,
"name_en": "Main Warehouse",
"name_ar": "المستودع الرئيسي",
"stock": 120
}
]
},
{
"id": 43,
"name_en": "Consulting Service",
"sku": "SVC-001",
"track_quantity": 0,
"inventories": []
}
],
"pagination": {
"count": 2,
"total": 2,
"perPage": "100",
"currentPage": "1",
"totalPages": 1
}
}

Only process inventories for products where track_quantity is 1. Products with track_quantity: 0 return an empty inventories array.

3. Filter by SKU or category (optional)

Filter by SKU
curl -X GET "https://api.qoyod.com/2.0/products?q[sku_eq]=BW-001" \
-H "Authorization: Bearer {your_access_token}"
Filter by category ID
curl -X GET "https://api.qoyod.com/2.0/products?q[category_id_eq]=7" \
-H "Authorization: Bearer {your_access_token}"

4. Paginate through all results

Check pagination.totalPages against pagination.currentPage. While currentPage is less than totalPages, increment the page parameter and repeat the request. Note that perPage and currentPage are returned as strings — cast them before comparing.

5. Retrieve a single product (optional)

Retrieve a single product
curl -X GET "https://api.qoyod.com/2.0/products/42" \
-H "Authorization: Bearer {your_access_token}"
Response — 200 OK
{
"product": {
"id": 42,
"name_en": "Blue Widget",
"sku": "BW-001",
"track_quantity": 1,
"inventories": [
{
"id": 3,
"name_en": "Main Warehouse",
"name_ar": "المستودع الرئيسي",
"stock": 120
}
]
}
}

6. Write stock quantities to your integrated system

For each product with track_quantity: 1, iterate over inventories and apply the stock value to the corresponding record in your integrated system. Match records by product.id if your integrated system stores Qoyod IDs, or by product.sku if it does not.

Field mapping

This section describes the fields from Qoyod's response that are relevant to reading inventory levels, and what each one represents in the integrated system. The direction here is Qoyod → integrated system: Qoyod is the source, and your system is the destination.

For the full request and response schemas, see the products reference.

Qoyod response fieldTypeIntegrated system conceptNotes
product.idintegerQoyod product IDUse as the primary match key if your integrated system stores Qoyod IDs
product.skustringSKUUse as the fallback match key if your integrated system does not store Qoyod IDs
product.track_quantityintegerInventory tracking enabled1 means stock data is present; 0 means stock is not tracked — skip the inventories array entirely
product.inventories[].idintegerLocation IDIdentifies which warehouse or storage location the stock figure belongs to
product.inventories[].name_enstringLocation nameHuman-readable label; use for display or logging, not for matching
product.inventories[].stockintegerQuantity on handThe figure to write to the integrated system for this product at this location

The track_quantity filter is load-bearing. Before reading any inventories entry, confirm the parent product has track_quantity: 1. Products with track_quantity: 0 always return an empty inventories array — there is no stock figure to read or write.

Matching strategy. If your integrated system was built by consuming the Qoyod product list, it likely stores product.id. Use that for matching. If your integrated system was built independently and uses SKUs as the shared key, use product.sku. Do not rely on product.name_en for matching — names are not guaranteed to be unique or stable.

Verification

After each poll cycle, confirm the results are correct before writing stock quantities to your integrated system.

Check inventories is non-empty for tracked products. Any product with track_quantity: 1 should have at least one entry in inventories if it has been involved in a stock transaction. If a tracked product returns an empty inventories array, it has not yet had any stock movement in Qoyod — see Edge cases and gotchas below.

Check stock values are plausible. The stock field is an integer. Negative values indicate stock that has been sold or consumed beyond what was received — this is a valid state in Qoyod, not a response error. If your integrated system does not allow negative quantities, apply a floor of zero on your side and log the discrepancy for investigation.

Check pagination.total matches your expectation. If you have 200 products in Qoyod and pagination.total returns 50, a filter parameter is likely narrowing the result set — verify your query parameters. If pagination.total is zero, check whether the filter you applied matches any products.

Cross-check a sample. After a full poll, spot-check two or three products by sending GET /2.0/products/{id} for each and confirming the stock figure in the single-product response matches what the list returned. This confirms the list and single-record endpoints agree for those products at the time of the check.

Error scenarios

This section covers the error responses documented in the spec for GET /2.0/products and GET /2.0/products/{id}. For the full error catalog and retry guidance, see Error handling.

200 OK — success. The response contains a products array (list endpoint) or a product object (single-product endpoint). This is the expected outcome. Proceed to process inventories for each tracked product.

401 Unauthorized — GET /2.0/products only. The spec documents a 401 response for the list endpoint. This means the access token or API key in the Authorization header is missing or invalid. Check that the header is present and that the credential has not expired or been revoked.

404 Not Found — GET /2.0/products (empty catalog). When no products match the query (or the catalog is empty), the list endpoint returns a 404 with the string body "We found nothing". This is not an error in the integration sense — it means the filter returned no results, or no products exist yet. Log it and skip the write step for this cycle.

404 Not Found — GET /2.0/products/{id} (product not found). When the requested product ID does not exist in Qoyod, the single-product endpoint returns a 404 with the string body "Product not found". This typically means the Qoyod product was deleted after your integrated system last synced its product list. Remove or deactivate the corresponding record in your integrated system and log the event.